/***************************************************************************
/
/	functions that manage user authentication and authorization
/	such as logging in and ensuring the user is validated for
/	the adminstration pages, and allowing the user to update their
/	info (email and password)
/
/**************************************************************************/

//import API's that are used for CommonsMultipartFile (managing files)
import org.springframework.web.multipart.commons.*



//the admincontroller class contains all the groovy methods used in the
//admistrative part of the smf application
class AdminController {


	//before running any adminstrative functions, ensure the user is logged in as admin
	def beforeInterceptor =
		[ action : this.&redirectIfNotAuthenticated, except : [ 'login', 'logoff', 'prepLogin' ] ]


	// ----------------------------------------
	//authorization methods


	//if user is not logged on disallow any other methods to be called
	//and redirect them back to login page
	def redirectIfNotAuthenticated() {

		//check that this user has already been authenticated
		if( session.adminUser == null ) {

			//user is not logged in! redirect to the logoff function
			flash.message = "invalid authorization"
			redirect( controller : 'admin', action : 'logoff' )

		}
	}


	//log user off and present the login page
	def logoff = {

		//ensure the user MUST log back in before viewing any of the admistration pages
		session.adminUser = null
		render( view : 'login' )

	}


	//validate user credentials; redirect to login page if invalid
	def login = {

		//attempt to authenticate the user based on the entered username/password
		if ( authenticateUser( params.username, params.password ) ) {

			//user is valid; direct user to the instructions page
			flash.message = null
			render( view : 'instructions' )

		} else {

			//username was invalid; redirect user back to login page and display 'invalid' message
			flash.message = "invalid username/password"
			render( view : 'login' )

		}
	}


	// authenthicate a user based on a username/password combination in the database
	// input parameter: enteredName - the name entered by the user in the GSP
	// input parameter: enteredPassword - the password entered by the user in the GSP
	// output parameter: returns true if user is authenticated, false otherwise
	def authenticateUser( enteredName, enteredPassword ) {

		//ensure name and password were entered
		if ( enteredName != "" && enteredPassword != "" ) {

			//find a related user in the database and return false if there was no match
			def user = User.find( "from User as u where user_name like '" + enteredName + "'" )
			if ( user == null ) {

				return false

			}

			//check that this user's password matches the entered password
			if ( user.password == enteredPassword ) {

				//if so set user into session and return true
				session.adminUser = user
				return true

			} else {

				//else invalid info was entered; return false
				session.adminUser = null
				return false

			}

		} else {

			//user did not enter a name and password
			return false

		}
	}


	//direct user to login page
	def prepLogin = {

		render( view : 'login' )

	}


	//direct user to instructions page
	def instructions = {

		render( view : 'instructions' )

	}


	//direct user to user account page for the account they are logged in as
	def userAccount = {

		def currentUser = session.adminUser
		render( view : 'userAccount', model : [ currentUser : currentUser ] )

    }


    //save the email this user entered
    def updateEmail = {

		//update user's email with the one inputed
		def currentUser = User.get( params.id )
		currentUser.setEmail( params.email )
		currentUser.save()

		//check for errors during save
		if( !currentUser.hasErrors() ) {

			//update user info in session
			session.adminUser = currentUser
			flash.message = "email has been updated for "+ currentUser.userName

			//direct user to user account page
			userAccount()

		} else {

			//errors during save! re-show page with error messages
			render( view : 'userAccount', model : [ currentUser : currentUser ] )

		}
	}


    //save the email this user entered
    def updatePassword = {

		def currentUser = User.get( params.id )

		//validate old password matches existing
		if ( params.oldPassword == currentUser.getPassword() ) {

			//validate the new password is not empty
			if ( params.newPassword1 != null && !"".equals( params.newPassword1) ) {

				//and finally that the passwords match
				if ( params.newPassword1 == params.newPassword2 ) {

					//all good, change password
					currentUser.setPassword( params.newPassword1 )
					currentUser.save()
					session.adminUser = currentUser
					flash.message = "password has been updated for " + currentUser.userName
					//direct user to user account page
					userAccount()

				} else {

					//passwords do not match
					flash.message = "new passwords do not match!"

				}

			} else {

				//old password is invalid
				flash.message = "new password can not be empty!"

			}

		} else {

			//old password is invalid
			flash.message = "old password invalid!"

		}

		//any errors we redirect back to this page with approriate message for user
		render( view : 'userAccount', model : [ currentUser : currentUser ] )

	}




/***************************************************************************
/
/	methods dealing with the management of reports for the admin user,
/	allows user to enter criteria, choose a report and view results
/
/**************************************************************************/




	//direct user to reports selection page
	def reportSelection = {

	   	render( view : 'reports' )

    }


	// check the validation of the date input from user.
	// the date are selected from the drop-down menu on the webpage
	def isInputCompleteForReport(inputData) {

		if( ( inputData.inputStart_day == null ) ||
			( inputData.inputStart_month == null ) ||
			( inputData.inputStart_year == null ) ||
			( inputData.inputEnd_day == null ) ||
			( inputData.inputEnd_month == null ) ||
			( inputData.inputEnd_year == null ) ) {

			return false

		} else {

			return true

		}
	}


	// reformat the string of start date
	def getStartDate(params) {

		if ( isInputCompleteForReport(params) ){

			def startDate = params.inputStart_month + "/" + params.inputStart_day + "/" + params.inputStart_year
			return startDate

		} else {

			return null

		}

	}

	// reformat the string of end date
	def getEndDate(params) {

		if ( isInputCompleteForReport(params) ){

			def endDate = params.inputEnd_month + "/" + params.inputEnd_day + "/" + params.inputEnd_year
			return endDate

		} else {

			return null

		}

	}


	//show the email report list by using search criteria  (the start date and end date)
	def emailReport = {

		def startDate = getStartDate(params)
		def endDate = getEndDate(params)


		// check the validation of the start date and end date before query from database
		if (( startDate != null ) && ( endDate != null )) {

			def results = InfoRequest.findAllByDateCreatedBetween( new Date( startDate ), new Date( endDate ) )

			return [ emailReportList : results ]

		} else {

			render( view : 'reports' )

		}
	}


	//show a particular instance of a email record (inforequest)
	def emailShow = {

		def infoRequest = InfoRequest.get( params.id )
		if( !infoRequest ) {

			flash.message = "InfoRequest not found with id ${params.id}"
			redirect( action : emailReport )

		} else {

			return [ infoRequest : infoRequest ]

		}
	}


	//show the activity report list by using search criteria  (the start date and end date)
	def activityReport = {

		def startDate = getStartDate(params)
		def endDate = getEndDate(params)


		// check the validation of the start date and end date before query from database
		if (( startDate != null ) && ( endDate != null )) {

			def results = ReferralLog.findAllByDateCreatedBetween( new Date( startDate ), new Date( endDate ) )

			return [ referralReportList : results ]

		} else {

			render( view : 'reports' )

		}

	}


	//show the donation report list by using search criteria  (the start date and end date)
	def donationReport = {

		def startDate = getStartDate(params)
		def endDate = getEndDate(params)


		// check the validation of the start date and end date before query from database
		if (( startDate != null ) && ( endDate != null )) {

			def results = Donation.findAllByDateCreatedBetween( new Date( startDate ), new Date( endDate ) )

			return [ donationReportList : results ]

		} else {

			render( view : 'reports' )

		}

	}


	//show a particular instance of a donation record
	def donationShow = {

        def donation = Donation.get( params.id )

        if( !donation ) {

            flash.message = "Donation not found with id ${params.id}"
            redirect( action : donationReport )

        } else {

			return [ donation : donation ]

		}
	}




/***************************************************************************
/
/	methods that deal with content management (updating, adding, and
/	deleting stories) - includes adding and deleting images for each story
/
/**************************************************************************/



	//show the entire story list
    def storyList = {

        [ storyList: Story.list( params ) ]

    }


	//show a particular instance of a story
    def storyShow = {

        def story = Story.get( params.id )

        if( !story ) {

            flash.message = "Story not found with id ${params.id}"
            redirect( action : storyList )

        } else {

			return [ story : story ]

		}
    }


    //goto the edit page for an 'additional image' record
	def storyImageEditText = {

		def storyImage = StoryImage.get( params.additionalImageId )
		return [ storyImage : storyImage ]

	}


	//update the text entered by the user for an additional image
	def storyImageSaveText = {

		def storyImage = StoryImage.get( params.id )
		storyImage.properties = params
		storyImage.save()
		flash.message = "additional image text updated"
		redirect( action : storyShow, id : storyImage.story.id )

	}


	//dont save changes, just redirect to the show page for the related story
	def storyImageCancelEdit = {

		redirect(action:storyShow, id : params.storyId)

	}


	//get a story from the database (based on the id) that is to be edited
    def storyEdit = {

        def story = Story.get( params.id )

        if( !story ) {

            flash.message = "Story not found with id ${params.id}"
            redirect( action : storyList )

        } else {

            return [ story : story ]

        }
    }


	//update a story based on user input; first validate all constraints are met
    def storyUpdate = {

		//find the approriate stroy record
        def story = Story.get( params.id )
        if( story ) {

            story.properties = params
            if( !story.hasErrors() && story.save() ) {

				//save the story if there are no errors
                flash.message = "Story ${params.id} updated"
                redirect( action : storyShow, id : story.id )

            } else {

				//back to edit page if there are errors (will present errors to user)
                render( view : 'storyEdit', model : [ story:story ] )

            }

        } else {

			//warn user that the story could not be found
            flash.message = "Story not found with id ${params.id}"
            redirect( action : storyEdit, id : params.id )

        }
    }


	//prep a brand new story
    def storyCreate = {

        def story = new Story()
        story.properties = params
        return [ 'story' : story ]

    }


	//save a new story record to the database
    def storySave = {

        def story = new Story( params )
        if( !story.hasErrors() && story.save() ) {

            flash.message = "Story created"
            redirect( action : storyShow, id : story.id )

        } else {

            render( view : 'storyCreate', model : [ story : story ] )

        }
    }


	//replace a default image for a story
	def replaceStoryDefaultImage = {

		def fileIn = request.getFile( 'file' )

		//check there is an actual file
		if( fileIn == null || fileIn.empty ) {

		  	flash.message = 'image field can not be empty'

		} else {

		   	//check that this file is gif or jpg
		   	if ( ImageManager.isFileTypeValidPicture( fileIn ) ) {

				//ensure it is under a pre-defined size
				if ( ImageManager.isFileSizeWithinLimit( fileIn ) ) {

					//create a unique name for the picture and upload it to our images folder
					String newFileName = ImageManager.createUniqueFileName( fileIn.getOriginalFilename() )

					//upload the file to our image directory, and update the name in this story record
					fileIn.transferTo( new File( AppConstant.IMAGE_DIRECTORY + newFileName ) )
					ImageManager.updateDefaultPictureForStory( newFileName, params.storyId )

					flash.message = 'new default image uploaded'


				} else {

					flash.message = 'file to large'

				}

			} else {

				flash.message = 'file must be jpg or gif'

			}
		}

		//always redirect back to this 'show' page
		redirect( action : storyShow, id : params.storyId )

	}


	//remove value from the default image field for this story
	def deleteStoryDefaultImage = {

		//set the default pic name to nothing
		def story = Story.get( params.storyId )
		story.defaultPictureName = null
		story.save()
		flash.message = 'default image deleted'

		// redirect back to this 'show' page
		redirect( action : storyShow, id : params.storyId )

	}


	//add a new image to a particular story record
	def uploadAdditionalStoryImage = {

		def fileIn = request.getFile('file')

		//ensure user entered in a file
		if( fileIn == null || fileIn.empty ) {

		  	flash.message = 'new additional image field cannot be empty'

		} else {

		   	//check that this file is gif or jpg
			if ( ImageManager.isFileTypeValidPicture( fileIn ) ) {

				//ensure it is under a pre-defined size
				if (ImageManager.isFileSizeWithinLimit( fileIn ) ) {

					//create a unique name for the picture and upload it to our images folder
					String newFileName = ImageManager.createUniqueFileName( fileIn.getOriginalFilename() )

					//upload the file to our image directory, and create a new StoryImage
					//record for this story
					fileIn.transferTo( new File( AppConstant.IMAGE_DIRECTORY + newFileName ) )
					ImageManager.addAdditionalImageForStory( newFileName, params.storyId )

					flash.message = 'new default image uploaded'


				} else {

					flash.message = 'file to large'

				}

			} else {

				flash.message = 'file must be jpg or gif'

			}
		}

		//always redirect back to this 'show' page
		redirect( action : storyShow, id : params.storyId)

	}


	//delete the selected additional image record for this story
	def deleteAdditionalImage = {

		//find the record in database and delete it
		def storyImage = StoryImage.get( params.additionalImageId )
        storyImage.delete()
		flash.message = 'additional image deleted'

		// redirect back to this 'show' page
		redirect( action : storyShow, id : params.storyId )

	}
}
